<?php

/**
 * @author: Daniel Cisek
 * Class describing product in store
 */
class Product {
    /**
     * Constant declaring value, by which action will be recognized 
     */

    const ACTION_DELETE = 'DELETE',
            ACTION_INSERT = 'INSERT',
            ACTION_UPDATE = 'UPDATE';

    /**
     * Product ID, as in database
     * @var int
     */
    private $id;

    /**
     * Product title
     * @var String
     */
    private $title;

    /**
     * Product Metascore from metacritic.com, ranging from 0 to 100
     * @var int;
     */
    private $metaScore;

    /**
     * Product description
     * @var String
     */
    private $description;

    /**
     * Game publisher
     * @var String
     */
    private $publisher;

    /**
     * Game category, e.g. RTS
     * @var String
     */
    private $category;

    /**
     * Game technical requirements
     * @var String
     */
    private $technicalRequirements;

    /**
     * Game price
     * @var float
     */
    private $price;

    /**
     * Game release date
     * @var Date
     */
    private $releaseDate;

    /**
     * URL containing game cover
     * @var String
     */
    private $coverURL;

    /**
     * Game video URL, prefferably from YouTube or Vimeo
     * @var String
     */
    private $videoURL;

    /**
     * Product comments array
     * @var Array
     */
    private $comments;

    /**
     * Game scores given out by users
     * @var float
     */
    private $score;

    /**
     * Game PEGI tags
     * @var PEGI
     */
    private $pegi;

    /**
     * Game count in storage
     * @var int
     */
    private $count;

    /**
     * Checks whether the product with given id exists
     * @param int $id
     * @return boolean 
     */
    public static function productExists($id) {
        $dbConnection = new DBConnection();
        $query = "SELECT id FROM games WHERE id = $id";
        if (count($dbConnection->executeQuery($query)) > 0)
            return true;
        return false;
    }

    /**
     * Returns a list of products matching the search field condition
     * @param Array $searchField
     * @param int $offset
     * @param int $count
     * @return Array 
     */
    public static function search($searchField, $offset, $count) 
    {
        $dbConnection = new DBConnection();
        $query = "SELECT (SELECT COUNT(id) FROM games WHERE %s), g.id, title, price, description, coverURL,
                    (SELECT AVG(grade) FROM grades WHERE id = g.id) AS grade
                    FROM games g
                    WHERE %s
                    ORDER BY g.id DESC
                    LIMIT $offset, $count";
        if (isset($searchField['category'])) {
            $val = "catName = '{$searchField['category']}'";
            $query = sprintf($query, $val, $val);
        }
        return $dbConnection->executeQuery($query);
    }

    /**
     * Returns product count matching the condition
     * @param string $condition
     * @return Array
     */
    public static function getProductCount($condition = null) 
    {
        $dbConnection = new DBConnection();
        $query = "SELECT COUNT(id) AS count FROM games ";
        if ($condition != null)
            $query .= "WHERE $condition";
        $result = $dbConnection->executeQuery($query);
        $count = $result[0]['count'];
        return $count;
    }
    
    /**
     * Adds product to database
     * @param array $data
     * @return string|boolean 
     */
    public static function addProduct($data) 
    {
        $errors = array();
        $targetPath = '';
        if (isset($data['cover']) && strstr($data['cover']['type'], 'image')) {
            $filename = strtolower(str_replace(' ', '', $data['title']));
            $extension = substr($data['cover']['name'], strrpos($data['cover']['name'], '.'));
            $filename .= $extension;
            $targetPath = "img/covers/$filename";
            move_uploaded_file($data['cover']['tmp_name'], $targetPath);
            unset($data['cover']);
        }
        $data['coverURL'] = $targetPath;
        $pegiTags = array();
        $pegiTags[] = $data['PegiAge'];
        if (isset($data['PegiTag']))
            foreach ($data['PegiTag'] as $tag)
                $pegiTags[] = $tag;
        unset($data['PegiAge']);
        unset($data['PegiTag']);
        $query = "INSERT INTO games VALUES (default, :catName, :publisherName, :title, :description, 
            :technicalRequirements, :releaseDate, :metascore, :coverURL, :videoURL, :price, :count)";
        $pegiQuery = "INSERT INTO gamespegitags VALUES";
        $dbConnection = new DBConnection();
        $id = $dbConnection->executeUpdate($query, $data, true);
        if (!is_string($id)) {
            $errors[] = "Wystąpił błąd w trakcie dodawania produktu.";
            return $errors;
        }
        foreach ($pegiTags as $tag)
            $pegiQuery .= "($id, $tag),";
        $pegiQuery = substr($pegiQuery, 0, -1);
        if (!$dbConnection->executeUpdate($pegiQuery)) {
            $deleteQuery = "DELETE FROM games WHERE id = $id";
            $dbConnection->executeUpdate($deleteQuery);
            $errors[] = "Wystąpił błąd w trakcie dodawania produktu.";
        }
        if (count($errors) > 0)
            return $errors;
        return true;
    }

    /**
     * Lists avaible categories
     * @return Array
     */
    public static function listCategories() {
        $dbConnection = new DBConnection();
        $query = "SELECT catName, description, 
                    (SELECT COUNT(id) FROM games WHERE catName = c.catName) AS count
                    FROM categories c
                    ORDER BY catName ASC";
        $result = $dbConnection->executeQuery($query);
        return $result;
    }

    /**
     * Manages categorie, according to action type passed
     * @param string $actionType
     * @param Array $data
     * @return string
     * @throws Exception 
     */
    public static function manageCategories($actionType, $data) {
        $dbConnection = new DBConnection();
        if (!is_array($data))
            throw new Exception('Data expected to be array, ' . gettype($data) . ' given');
        switch ($actionType) {
            case self::ACTION_DELETE:
                $query = "DELETE FROM categories WHERE catName = ?";
                $statusText = "Kategoria usunięta pomyślnie.";
                break;
            case self::ACTION_INSERT:
                $query = "INSERT INTO categories VALUES(:id, :description)";
                $statusText = "Kategoria dodana pomyślnie";
                break;
            case self::ACTION_UPDATE:
                $query = "UPDATE categories SET description = ? WHERE catName = ?";
                $statusText = "Kategoria zaktualizowana pomyślnie";
                break;
        }
        if ($dbConnection->executeUpdate($query, $data)) {
            $data = array(
                'text' => $statusText,
                'success' => true,
            );
        } else {
            $data = array(
                'text' => 'Operacja zakończona niepowodzeniem.',
                'success' => false,
            );
        }
        return $data;
    }

    /**
     * Lists all avaible publishers
     * @return Array
     */
    public static function listPublishers() {
        $dbConnection = new DBConnection();
        $query = "SELECT publisherName,
                    (SELECT COUNT(id) FROM games WHERE publisherName = p.publisherName) AS count
                    FROM publishers p";
        $result = $dbConnection->executeQuery($query);
        return $result;
    }

    /**
     * Manages publishers, according to passed action type
     * @param string $actionType
     * @param Array<> $data
     * @return string
     * @throws Exception 
     */
    public static function managePublishers($actionType, $data) {
        $dbConnection = new DBConnection();
        if (!is_array($data))
            throw new Exception('Data expected to be array, ' . gettype($data) . ' given');
        switch ($actionType) {
            case self::ACTION_DELETE:
                $query = "DELETE FROM publishers WHERE publisherName = ?";
                $statusText = "Wydawca usunięty pomyślnie.";
                break;
            case self::ACTION_INSERT:
                $query = "INSERT INTO publishers VALUES(?)";
                $statusText = "Wydawca dodany pomyślnie";
                break;
            default:
                throw new Exception("$actionType has not been defined for this method");
                break;
        }
        if ($dbConnection->executeUpdate($query, $data)) {
            $data = array(
                'text' => $statusText,
                'success' => true,
            );
        } else {
            $data = array(
                'text' => 'Operacja zakończona niepowodzeniem.',
                'success' => false,
            );
        }
        return $data;
    }
    
        /**
     * Lists a number of products from the given offset, specified by the count
     * @param int $offset
     * @param int $count
     * @return Array<Array<>> 
     */
    public static function listProducts($offset, $count) {
        $dbConnection = new DBConnection();
        $query = "SELECT g.id, title, price, description, coverURL,
                    (SELECT AVG(grade) FROM grades WHERE id = g.id) AS grade
                    FROM games g
                    ORDER BY g.id DESC 
                    LIMIT $offset, $count";
        return $dbConnection->executeQuery($query);
    }
    
    /**
     * Constructor with ID, that gets data from database
     */
    public function __construct($id) {
        $this->id = $id;
        $this->getFromDatabase();
    }

    /**
     * Function getting from database product data (with given id)
     */
    private function getFromDatabase() {
        $dbConnection = new DBConnection();
        $query = "SELECT g.id, catName, publisherName, title, description, technicalRequirements, releaseDate, 
                    metaScore, coverUrl, videoUrl, price, count, AVG(grade) AS grade FROM games g
                    JOIN grades gr ON gr.id = g.id
                    WHERE g.id = {$this->id}";

        $result = $dbConnection->executeQuery($query);
        $result = $result[0];
        $this->title = $result['title'];
        $this->category = $result['catName'];
        $this->publisher = $result['publisherName'];
        $this->description = $result['description'];
        $this->technicalRequirements = $result['technicalRequirements'];
        $this->releaseDate = $result['releaseDate'];
        $this->metaScore = $result['metaScore'];
        $this->coverURL = $result['coverUrl'];
        $this->videoURL = $result['videoUrl'];
        $this->price = $result['price'];
        $this->count = $result['count'];
        if ($result['grade'] == null)
            $this->score = '';
        else
            $this->score = intval($result['grade']);
        $this->pegi = new PEGI($this);
        $this->comments = Comment::listCommentsForProduct($this);
    }

    /**
     * Function returning formatted html code with product data
     * @return String
     */
    public function displayProductDetails() {
        $productLink = $_SERVER['PHP_SELF'] . '?' . $_SERVER['QUERY_STRING'];
        $html = "\t<img class='cover' src='{$this->coverURL}' width='174' alt='{$this->title}' />\n";
        $html .= "\t<p class='title'><a href='$productLink'>$this->title</a></p>\n";
        $html .= "\t<p class='rating{$this->score}'>";
        if ($this->score == '')
            $html .= 'Brak oceny';
        $html .= "</p>\n";
        $html .= "\t<div class='addtocart'><a href='index.php?action=AddToBasket&id={$this->id}'>Dodaj do koszyka</a></div>\n";
        $html .= "\t<p class='price'>{$this->price} zł</p>\n";
        $html .= "\t<p class='genre'>{$this->category}</p>\n";
        $html .= "\t<p class='metascore'>Metascore: {$this->metaScore}/100</p>\n";
        $html .= "\t<p id='pegi'>" . $this->pegi->displayTagsForProduct() . "</p>\n";
        $html .= "\t<p class='description'>{$this->description}</p>\n";
        if ($this->videoURL != '')
            $html .= "\t<video id='player' src='$this->videoURL'></video>";
        return $html;
    }

    /**
     * Function that changes product data and saves it in database
     * @param String $title 
     * @param String $publisher
     * @param String $price
     * @param String $genre
     * @param String $technicalRequirements 
     */
    public function changeProductData($title, $publisher, $price, $genre, $technicalRequirements) {
        
    }

    public function __set($key, $value) {
        if (property_exists($this, $key))
            $this->$key = $value;
        else
            throw new Exception("Property $key does not exist in class " . __CLASS__);
    }

    public function __get($key) {
        if (property_exists($this, $key))
            return $this->$key;
        else
            throw new Exception("Property $key does not exist in class " . __CLASS__);
    }

}

?>